/*
 * @Author: new-wang
 * @Date: 2025-08-26 18:04:58
 * @LastEditors: new-wang
 * @LastEditTime: 2025-09-11 14:30:18
 * @FilePath: \nest-demo\src\module\system\user\user.service.ts
 * @Description: 用户服务
 */
import { Injectable } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { LoginDto, RegisterDto } from '../auth/dto'
import { UserEntity } from 'src/entityAll/entities/sys-user.entity'
import { UserLoginLogEntity } from 'src/entityAll/entities/UserLoginLog'
import { UserRoles as UserRolesEntity } from 'src/entityAll/entities/UserRoles'
import { ResultData } from 'src/common/utils/result'
import { GenerateUUID, Uniq } from 'src/common/utils'
import * as bcrypt from 'bcrypt'
import { isEmail, isPhoneNumber } from 'class-validator'
import { DelFlagEnum, StatusEnum } from 'src/common/enum'
import { ClientInfoDto } from 'src/common/decorators/clientInfo.decorator'
import { JwtService } from '@nestjs/jwt'
import { RoleService } from '../role/role.service'

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepo: Repository<UserEntity>,
    @InjectRepository(UserLoginLogEntity)
    private readonly loginLogRepo: Repository<UserLoginLogEntity>,
    @InjectRepository(UserRolesEntity)
    private readonly userRolesEntity: Repository<UserRolesEntity>,
    private readonly roleService: RoleService,
    private readonly jwtService: JwtService,
  ) {
    this.saltRounds = bcrypt.genSaltSync(10)
  }
  saltRounds: string | number
  /**
   * 用户注册
   * @param user 注册用户信息
   * @returns
   */
  async register(user: RegisterDto) {
    // 检查用户名是否唯一 @TODO email,phone等唯一性
    const checkUserNameUnique = await this.userRepo.findOne({
      where: {
        username: user.username,
      },
      select: ['username'],
    })
    if (checkUserNameUnique) {
      return ResultData.fail(1001, '用户名已存在')
    }

    // uuid 暂不校验唯一性，重复性概率极低
    const uuid = GenerateUUID()
    // 对密码进行哈希处理
    // const passwordHash = await bcrypt.hash(user.password, saltRounds);//异步
    const passwordHash = bcrypt.hashSync(user.password, this.saltRounds) //同步

    const userObj = {
      ...user,
      uuid,
      passwordHash,
    }
    const newUser = await this.userRepo.save(userObj)
    // 返回结果时移除密码哈希等敏感信息
    const {
      passwordHash: _,
      confirmPassword,
      password,
      id,
      ...safeUser
    } = newUser
    return ResultData.ok(safeUser)
  }

  /**
   * 用户登录
   * @param user
   * @returns
   */
  async login(user: LoginDto, client: ClientInfoDto) {
    const accountObj = {
      account: user.account,
    }
    // 使用查询构建器创建灵活的查询条件
    const queryBuilder = this.userRepo
      .createQueryBuilder('user')
      .select([
        'user.id',
        'user.uuid',
        'user.systemId',
        'user.status',
        'user.passwordHash',
        'user.delFlag',
      ])
    // 根据输入类型优化查询条件
    if (isEmail(user.account)) {
      // 如果是邮箱，优先使用邮箱索引
      queryBuilder.where('user.email = :account', accountObj)
    } else if (isPhoneNumber(user.account)) {
      // 如果是手机号，优先使用手机号索引
      queryBuilder.where('user.phone = :account', accountObj)
    } else {
      // 否则使用用户名索引
      queryBuilder.where('user.username = :account', accountObj)
    }
    // 如果有系统代码，添加系统条件并利用复合索引
    if (user.systemCode) {
      queryBuilder.andWhere('user.systemId = :systemCode', {
        systemCode: user.systemCode,
      })
    }
    // 密码
    // queryBuilder.andWhere('user.password = :password', {
    //   password: user.password,
    // })
    // 执行查询
    const data = await queryBuilder.getOne()
    // 为了避免精度丢失，TypeORM 默认将 bigint 类型作为字符串返回，暂不处理

    // 密码验证
    if (!(data && bcrypt.compareSync(user.password, data.passwordHash))) {
      return ResultData.fail(1001, '账号或密码错误')
    }

    // 是否删除
    if (data.delFlag == DelFlagEnum.DELETE) {
      return ResultData.fail(1001, '您已被禁用，如需正常使用请联系管理员')
    }
    // 是否停用
    if (data.status == StatusEnum.STOP) {
      return ResultData.fail(1001, '您已被停用，如需正常使用请联系管理员')
    }

    // 更新用户最后登录信息
    await this.userRepo.update(
      {
        uuid: data.uuid,
      },
      {
        lastLoginTime: new Date(),
        lastLoginIp: client.ipaddr,
      },
    )

    // 添加登录记录
    const loginLog = this.loginLogRepo.create({
      userUuid: data.uuid,
      systemId: data.systemId === null ? undefined : data.systemId,
      loginIp: client.ipaddr,
      userAgent: client.userAgent,
      loginResult: 1, // 1:成功, 0:失败
    })
    await this.loginLogRepo.save(loginLog)

    // @TODO 获取权限信息
    // const permissions = await this.getUserPermissions(data.id, data.systemId)

    // console.log('permissions', permissions)

    // token
    const token = this.createToken({ uuid: data.uuid })

    // @TODO 用户信息缓存到redis

    // const userData = await this.getUserInfo(data.uuid)

    return ResultData.ok(data)
  }

  /**
   * 从数据声明生成令牌
   * @param payload 数据声明
   * @return 令牌
   */
  createToken(payload: { uuid: string; userId?: number }): string {
    const accessToken = this.jwtService.sign(payload)
    return accessToken
  }

  /**
   * 获取用户权限信息
   * @param _uuid 用户uuid
   */
  async getUserPermissions(id: number, systemId?: any) {
    console.log('id', id)
    console.log('systemId', systemId)

    // 根据角色赋予权限
    // 1、先从用户角色表中获取角色ID列表，
    // 2、再根据角色ID列表获取角色信息 (由于角色分系统，所以如果需要 某角色 有所有权限不能使用固定的角色id来处理)
    // 3、根据角色信息获取权限ids
    // 4、根据权限ids获取权限列表
    // 5、整合权限列表，去重
    // 6、返回结果

    const userRoles = await this.getRoleList(id, systemId)
    // 角色等级
    // WX_SUPER_ADMIN_ROLE 超级管理员角色 所有权限，
    // WX_ORDINARY_ADMIN_ROLE 普通管理员角色，
    // WX_BASE_ROLE 普通角色,
    // 超级管理员角色 和 普通管理员角色 固定的权限，不用查询角色权限关系表
    const roleGrace = userRoles.map((role) => role.grace).filter(role => role !== null)
    const uniqGrace = Uniq(roleGrace)
    const roleIds = userRoles.map((role) => role.id)
    const UniqRoleIds = Uniq(roleIds)

    console.log('roleGrace--',roleGrace)
    // const userPermissions = await this.roleService.getRolePermissions(userRoles,systemId)

    // console.log('userPermissions--', userPermissions)
    console.log('用户的角色信息--', userRoles)
    return []
  }

  /**
   * 获取用户所有角色信息
   * @param id 用户id
   * @returns 角色ID列表
   * @description 
   * // 1、先从用户角色关联表中获取角色ID列表(查询 用户-角色关系表)，
   * // 2、再根据角色ID列表获取角色信息（查询角色表）
   */
  async getRoleList(id: number, systemId?: any) {
    const roleIdList = await this.userRolesEntity.find({
      where: {
        userId: id,
        ...(systemId ? { systemId } : {}),
      },
      // select: ['id'],
    })
    const roleIds = roleIdList.map((item) => item.id)
    const UniqRoleIds = Uniq(roleIds)
    const roleInfo = await this.roleService.getRoleByIds(UniqRoleIds)
    return roleInfo
  }
}
